package com.mdp.workflow.biz.ru.service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.mdp.core.service.BaseService;
import com.mdp.workflow.biz.ru.entity.ProcinstNodeInfo;
import com.mdp.workflow.biz.ru.mapper.ProcinstNodeInfoMapper;
import com.mdp.workflow.comm.dict.CandidateStrategy;
import com.mdp.workflow.comm.tools.FlowModelUtils;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.bpmn.model.UserTask;
import org.flowable.engine.RepositoryService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.Predicate;

/**
 * 父类已经支持增删改查操作,因此,即使本类什么也不写,也已经可以满足一般的增删改查操作了.<br> 
 * 组织 com.mdp  顶级模块 workflow 大模块 ru 小模块 <br>
 * 实体 ProcinstNodeInfo 表 mdp_ru_procinst_node_info 当前主键(包括多主键): id; 
 ***/
@Service
public class ProcinstNodeInfoService extends BaseService<ProcinstNodeInfoMapper,ProcinstNodeInfo> {
	static Logger logger =LoggerFactory.getLogger(ProcinstNodeInfoService.class);

	@Lazy
	@Autowired
	RepositoryService repositoryService;


	/**
	 * 自定义查询，支持多表关联
	 * @param page 分页条件
	 * @param ew 一定要，并且必须加@Param("ew")注解
	 * @param ext 如果xml中需要根据某些值进行特殊处理，可以通过这个进行传递，非必须，注解也可以不加
	 * @return
	 */
	public List<Map<String,Object>> selectListMapByWhere(IPage page, QueryWrapper ew, Map<String,Object> ext){
		return baseMapper.selectListMapByWhere(page,ew,ext);
	}


	/** 请在此类添加自定义函数 */
	@Autowired
	ProcinstNodeInfoCacheService procinstNodeInfoCacheService;



	public List<ProcinstNodeInfo> getNodeInfosFromCache(String procInstId){
		List<ProcinstNodeInfo> nodeInfos=new ArrayList<>();
		List<ProcinstNodeInfo> nodeInfoVos=procinstNodeInfoCacheService.getNodeInfos(procInstId);
		if(nodeInfoVos!=null) {
			return nodeInfoVos;
		}
		ProcinstNodeInfo queryNode=new ProcinstNodeInfo();
		queryNode.setProcInstId(procInstId);
		nodeInfos=this.selectListByWhere(queryNode);
		if(nodeInfos==null || nodeInfos.size()==0) {
			nodeInfoVos=new ArrayList<ProcinstNodeInfo>();
			procinstNodeInfoCacheService.putNodeInfos(procInstId, nodeInfoVos);
			return nodeInfoVos;
		}

		procinstNodeInfoCacheService.putNodeInfos(procInstId, nodeInfos);
		return nodeInfos;

	}

	/**
	 * 新增项目时，同时新增项目团队及小组组员等
	 * @param procInstId
	 * @param procinstNodeInfoList
	 */
	public void addNodeInfos(String procInstId,List<ProcinstNodeInfo> procinstNodeInfoList) {
		List<ProcinstNodeInfo> nodes=new ArrayList<>();
 		for (ProcinstNodeInfo ProcinstNodeInfo : procinstNodeInfoList) {
			ProcinstNodeInfo node=new ProcinstNodeInfo();
			ProcinstNodeInfo.setId(this.createKey("id"));
			BeanUtils.copyProperties(ProcinstNodeInfo, node);
			node.setProcInstId(procInstId);
			nodes.add(node);
		}
		if(nodes.size()>0) {
			this.batchInsert(nodes);
		}
		procinstNodeInfoCacheService.putNodeInfos(procInstId, null);
	}
	//更新项目团队
	public List<ProcinstNodeInfo> updateNodeInfos(String procInstId,List<ProcinstNodeInfo> ProcinstNodeInfoList) {
		ProcinstNodeInfo node = new ProcinstNodeInfo();
		node.setProcInstId(procInstId);
		List<ProcinstNodeInfo> nodeListDb = this.selectListByWhere(node);
		List<ProcinstNodeInfo> delNodeInfos=new ArrayList<>();

		//查出需要删除的组进行删除组及关联组成员
		nodeListDb.forEach(g->{

			if(ProcinstNodeInfoList.stream().noneMatch(new Predicate<ProcinstNodeInfo>() {

				@Override
				public boolean test(ProcinstNodeInfo t) {

					return t.getActId().equals(g.getActId());
				}
			})) {
				delNodeInfos.add(g);
			}

		});
		if(delNodeInfos.size()>0) {
			delNodeInfos.forEach(g->{
				ProcinstNodeInfo delNodeInfo=new ProcinstNodeInfo();
				delNodeInfo.setId(g.getId());
				this.deleteByPk(delNodeInfo);
				//xmRecordService.addXmNodeInfoRecord(procInstId, g.getId(),"项目-团队-删除小组", "删除小组["+g.getNodeInfoName()+"]",g.getId(),null);
			});

		}

		//查询新增的组进行增加并添加组成员,同时查出修改的组进行更新组及成员
		List<ProcinstNodeInfo> ProcinstNodeInfoAdd=new ArrayList<>();
		List<ProcinstNodeInfo> ProcinstNodeInfoEdit=new ArrayList<>();
		ProcinstNodeInfoList.forEach(vo->{
			if(nodeListDb.stream().noneMatch(new Predicate<ProcinstNodeInfo>() {

				@Override
				public boolean test(ProcinstNodeInfo t) {

					return t.getActId().equals(vo.getActId());
				}
			})) {
				ProcinstNodeInfoAdd.add(vo);
			}else {
				ProcinstNodeInfoEdit.add(vo);
			}
		});
		if(ProcinstNodeInfoAdd.size()>0) {
			ProcinstNodeInfoAdd.forEach(gvo -> {
				gvo.setId(this.createKey("id"));
				gvo.setProcInstId(procInstId);
				ProcinstNodeInfo g = new ProcinstNodeInfo();
				BeanUtils.copyProperties(gvo,g);
				this.insert(g);
				//xmRecordService.addXmNodeInfoRecord(procInstId, gvo.getId(),"项目-团队-新增小组", "新增小组["+gvo.getNodeInfoName()+"]及以下组员："+StringUtils.arrayToDelimitedString(addNodeUsernames.toArray(), ","),JSON.toJSONString(gvo),null);

			});
		}
		if(ProcinstNodeInfoEdit.size()>0) {
  			ProcinstNodeInfoEdit.forEach(gvo -> {

				gvo.setProcInstId(procInstId);
				ProcinstNodeInfo g = new ProcinstNodeInfo();
				BeanUtils.copyProperties(gvo,g);
				this.updateSomeFieldByPk(g);
			});
		}

		procinstNodeInfoCacheService.putNodeInfos(procInstId, null);
		return ProcinstNodeInfoList;
	}


	public void clearCacheNodeInfos(String procInstId) {
		procinstNodeInfoCacheService.putNodeInfos(procInstId, null);
	}
	public ProcinstNodeInfo getNodeInfoFromCache(String procInstId, String actId) {
		List<ProcinstNodeInfo> vos=this.getNodeInfosFromCache(procInstId);
		if(vos==null || vos.size()==0) {
			return null;
		}else {
			for (ProcinstNodeInfo ProcinstNodeInfo : vos) {
				if(ProcinstNodeInfo.getActId().equals(actId)) {
					return ProcinstNodeInfo;
				}
			}
		}
		return null;
	}


	public List<ProcinstNodeInfo> getProcessNodeAssignees(String processDefinitionId) {
		// 1. 静态解析
		BpmnModel model = repositoryService.getBpmnModel(processDefinitionId);
		List<UserTask> userTasks = model.getMainProcess().findFlowElementsOfType(UserTask.class);
		List<ProcinstNodeInfo> nodeInfos=new ArrayList<>();
		for (UserTask userTask : userTasks) {
			String strategy= FlowModelUtils.parseCandidateStrategy(userTask);
			String param=FlowModelUtils.parseCandidateParam(userTask);
			CandidateStrategy.of(strategy).getDescription();
			ProcinstNodeInfo nodeInfo=new ProcinstNodeInfo();
			nodeInfo.setActId(userTask.getId());
			nodeInfo.setActName(userTask.getName());
			nodeInfo.setStrategy(strategy);
			nodeInfo.setStrategyParam(param);
			nodeInfo.setProcDefId(processDefinitionId);
			nodeInfos.add(nodeInfo);
		}
 	return nodeInfos;
	}
}

